home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 007 / jovept1.arc / INSERT.C < prev    next >
Text File  |  1985-05-30  |  12KB  |  566 lines

  1. /* insert.c */
  2.  
  3. /* JOVE/MSDOS. K. Mitchum 1/85 */
  4. /* Modifications for personal use only. */
  5. /* original code J. Payne LSRHS 5/83 */
  6. /* Ken Mitchum */
  7. /* University of Pittsburgh */
  8. /* Decision Systems Laboratory */
  9.  
  10.  
  11. /*
  12.    Jonathan Payne at Lincoln-Sudbury Regional High School 5/25/83
  13.   
  14.    Insert routines: the routine to Yank from the kill buffer
  15.    and to insert lines, and characters into the buffer.  */
  16.  
  17. #include "jove.h"
  18.  
  19. extern int RMargin;
  20.  
  21.  
  22.  
  23. #define CHUNKSIZE    40
  24.  
  25. /* Make a newline after `after' or course in `buf' */
  26.  
  27. LINE *
  28. listput(buf, after)
  29. BUFFER    *buf;
  30. LINE *after;
  31. {
  32.     LINE    *newline = nbufline();
  33.  
  34.     if (after == 0) {    /* First line in this list */
  35.         buf->b_zero = buf->b_dol = buf->b_dot = newline;
  36.         newline->l_next = newline->l_prev = 0;
  37.         return newline;
  38.     }
  39.     newline->l_prev = after;
  40.     newline->l_next = after->l_next;
  41.     after->l_next = newline;
  42.     if (newline->l_next)
  43.         newline->l_next->l_prev = newline;
  44.     else
  45.         if (buf)
  46.             buf->b_dol = newline;
  47.     return newline;
  48. }    
  49.  
  50. /* Global variables aren't that bad.  There is a point where one
  51.  * can go too far in trying to eliminate global variables on a 
  52.  * principle.  After all this isn't LISP or anything like that.
  53.  */
  54.  
  55. LineInsert()
  56. {
  57.     register int    num = exp;
  58.     char    newline[LBSIZE];
  59.     LINE    *newdot,
  60.         *olddot = curline;
  61.     int    oldchar = curchar;
  62.     int    atbegin = (!firstp(curline) && bolp());
  63.  
  64.     exp = 1;
  65.     if (atbegin)    /* This is mostly to make redisplay seem smart
  66.                but it also decreases the amount of copying
  67.                from one buffer to another */
  68.         BackChar();
  69.     strcpy(newline, &linebuf[curchar]);
  70.  
  71.     newdot = curline;
  72.     while (num--) {
  73.         newdot = listput(curbuf, newdot);    /* Put after newdot */
  74.         newdot->l_dline = putline("") | DIRTY;
  75.     }
  76.     linebuf[curchar] = '\0';    /* Shorten this line */
  77.     SavLine(curline, linebuf);
  78.     makedirty(curline);
  79.     curline = newdot;
  80.     curchar = 0;
  81.     strcpy(linebuf, newline);
  82.     makedirty(curline);
  83.     if (atbegin)
  84.         ForChar();
  85.     SetModified(curbuf);
  86.     IFixMarks(olddot, oldchar, curline, curchar);
  87. }    
  88.  
  89. LineAI()
  90. {
  91.     LineInsert();
  92.     whitesp(getline(curline->l_prev->l_dline, genbuf), linebuf);
  93. }
  94.  
  95. whitesp(from, to)
  96. register char    *from,
  97.         *to;
  98. {
  99.     char    c;
  100.     int    oldchar = curchar;
  101.  
  102.     while ((c = *from++) && (c == ' ' || c == '\t'))
  103.         insert(c, to, curchar++, 1, LBSIZE);
  104.     SetModified(curbuf);
  105.     IFixMarks(curline, oldchar, curline, curchar);
  106. }
  107.  
  108. len_error(flag)
  109. {
  110.     char    *mesg = "line too long";
  111.  
  112.     (flag == COMPLAIN) ? complain(mesg) : error(mesg);
  113. }
  114.  
  115. /* Insert num number of c's at offset atchar in a linebuf of LBSIZE */
  116.  
  117. insert(c, buf, atchar, num, max)
  118. char    c, *buf;
  119. {
  120.     register char    *pp, *pp1;
  121.     register int    len = atchar + strlen(&buf[atchar]);
  122.     int    numchars;    /* Number of characters to copy forward */
  123.  
  124.     if (len + num >= max)
  125.         len_error(COMPLAIN);
  126.     pp = &buf[len];
  127.     pp1 = &buf[len + num];
  128.     numchars = len - atchar;
  129.     while (numchars-- >= 0)
  130.         *pp1-- = *pp--;
  131.     pp = &buf[atchar];
  132.     while (num--)
  133.         *pp++ = c;
  134. }
  135.  
  136. /*
  137.  * Three situations:
  138.  *
  139.  * (1) We are at the end of the line in which case we just insert the char.
  140.  * (2) We are in the middle of the line on a normal character in which case
  141.  *     we replace that character with 'c'.
  142.  * (3) We are in the middle of a tab.  Here we insert the character unless
  143.  *     we are at the end of the tab stop in which case cover the tab with
  144.  *     'c'.
  145.  */
  146.  
  147. OverWrite()
  148. {
  149.     int    i, num;
  150.  
  151.     for (i = 0, num = exp, exp = 1; i < num; i++) {
  152.         if (!eolp())
  153.             DelNChar();
  154.         Insertc(LastKeyStruck);
  155.     }
  156. }
  157.  
  158. SelfInsert()
  159. {
  160.     Insertc(LastKeyStruck);
  161. }
  162.  
  163. Insertc(c)
  164. {
  165.     SetModified(curbuf);
  166.     makedirty(curline);
  167.     insert(c, linebuf, curchar, exp, LBSIZE);
  168.     IFixMarks(curline, curchar, curline, curchar + exp);
  169.     curchar += exp;
  170. }    
  171.  
  172. /*
  173.  * Tab in to the right place for c mode
  174.  */
  175.  
  176. CTab()
  177. {
  178.     if (strlen(linebuf) == 0)
  179.         c_indent();
  180.     Insertc('\t');
  181. }
  182.  
  183. QuotChar()
  184. {
  185.     int    c;
  186.  
  187.     if (c = (*Gtchar)())
  188.         Insertc(c);
  189. }
  190.  
  191. blankp(line)
  192. char    *line;
  193. {
  194.     register char    c;
  195.  
  196.     while (c = *line++)
  197.         if (c != ' ' && c != '\t')
  198.             return 0;
  199.     return 1;
  200. }
  201.  
  202. /* Insert the paren.  If in C mode and c is a '}' then insert the
  203.  * '}' in the "right" place for C indentation; that is indented 
  204.  * the same amount as the matching '{' is indented.
  205.  */
  206.  
  207. DoParen()
  208. {
  209.     BUFLOC    *bp;
  210.     int nomatch;
  211.     int    nx,
  212.         c = LastKeyStruck;
  213.     nomatch = 0;
  214.     if (c != ')' && c != '}')
  215.         complain((char *) 0);
  216.     if (c == '}' && IsFlagSet(globflags, CMODE))
  217.         if (blankp(linebuf)) {
  218.             Bol();        /* Beginning of line and */
  219.             DelWtSpace();    /* Delete white space */
  220.             c_indent();    /* insert the white space */
  221.         }
  222.     
  223.     Insertc(c);
  224.     if (IsFlagSet(globflags, MATCHING)) {
  225.         redisplay();
  226.         GotoDot();
  227.         BackChar();
  228.         if (NotInQuotes(linebuf, curchar)) {
  229.             if (bp = m_paren(c, curwind->w_top)) {
  230.                 nx = in_window(curwind, bp->p_line);
  231.                 if (nx != -1) {
  232.                     BUFLOC    b;
  233.  
  234.                     DOTsave(&b);
  235.                     SetDot(bp);
  236.                     redisplay();
  237.                     sleep(1);
  238.                     SetDot(&b);
  239.                 }
  240.             } else nomatch++;
  241.         }
  242.         ForChar();
  243.     }
  244.     if(nomatch) complain("Match to %c not in window",c);
  245.     return;
  246. }
  247.  
  248. c_indent()
  249. {
  250.     BUFLOC    *bp;
  251.  
  252.     bp = m_paren('}', curbuf->b_zero);
  253.     if (!bp)
  254.         return;
  255.     ignore(getright(bp->p_line, genbuf));
  256.     whitesp(genbuf, linebuf);
  257. }
  258.  
  259. AtMargin()
  260. {
  261.     int    open_kludge = 0;
  262.  
  263.     exp = 1;
  264.  
  265.     if (curline->l_next == 0) {
  266.         OpenLine();
  267.         open_kludge++;
  268.     }
  269.     DoJustify(curline, curline->l_next);
  270.     if (open_kludge)
  271.         DelNChar();
  272. }
  273.  
  274. Newline()
  275. {
  276.     /* If there is more than 2 blank lines in a row then don't make
  277.      * a newline, just move down one.
  278.      */
  279.  
  280.     if (exp == 1 && eolp() && curline->l_next &&
  281.             (getline(curline->l_next->l_dline,
  282.             genbuf)[0] == '\0') && curline->l_next->l_next &&
  283.             (getline(curline->l_next->l_next->l_dline,
  284.             genbuf)[0] == '\0')) {
  285.         SetLine(curline->l_next);
  286.         return;
  287.     }
  288.     LineInsert();
  289. }
  290.  
  291. TextInsert()
  292. {
  293.     Insertc(LastKeyStruck);
  294.     if ((curchar > RMargin) && LastKeyStruck != ' ')
  295.         AtMargin();
  296. }
  297.  
  298. ins_str(str)
  299. register char    *str;
  300. {
  301.     register char    c;
  302.     int    pos = curchar;
  303.  
  304.     while (c = *str++) {
  305.         if (c == '\n')
  306.             continue;
  307.         insert(c, linebuf, curchar++, 1, LBSIZE);
  308.     }
  309.     IFixMarks(curline, pos, curline, curchar);
  310.     makedirty(curline);
  311. }
  312.  
  313. linecopy(onto, atchar, from)
  314. register char    *onto, *from;
  315. register int    atchar;
  316. {
  317.     char    *base = onto;
  318.  
  319.     onto += atchar;
  320.  
  321.     while (*onto = *from++)
  322.         if (onto++ >= &base[LBSIZE - 2])
  323.             len_error(ERROR);
  324. }
  325.  
  326. OpenLine()
  327. {
  328.     int    num = exp;
  329.  
  330.     LineInsert();    /* Open the lines... */
  331.     DoTimes(BackChar, num);
  332. }
  333.  
  334. BUFLOC *
  335. DoYank(fline, fchar, tline, tchar, atline, atchar, whatbuf)
  336. LINE    *fline, *tline, *atline;
  337. BUFFER    *whatbuf;
  338. {
  339.     register LINE    *newline;
  340.     static BUFLOC    bp;
  341.     char    save[LBSIZE],
  342.         buf[LBSIZE];
  343.     LINE    *startline = atline;
  344.     int    startchar = atchar;
  345.  
  346.     SetModified(curbuf);
  347.     lsave();
  348.     ignore(getright(atline, genbuf));
  349.     strcpy(save, &genbuf[atchar]);
  350.  
  351.     ignore(getright(fline, buf));
  352.     if (fline == tline)
  353.         buf[tchar] = '\0';
  354.  
  355.     linecopy(genbuf, atchar, &buf[fchar]);
  356.     atline->l_dline = putline(genbuf);
  357.     makedirty(atline);
  358.  
  359.     fline = fline->l_next;
  360.     while (fline != tline->l_next) {
  361.         newline = listput(whatbuf, atline);
  362.         newline->l_dline = fline->l_dline;
  363.         makedirty(newline);
  364.         fline = fline->l_next;
  365.         atline = newline;
  366.         atchar = 0;
  367.     }
  368.  
  369.     ignore(getline(atline->l_dline, genbuf));
  370.     atchar += tchar;
  371.     linecopy(genbuf, atchar, save);
  372.     atline->l_dline = putline(genbuf);
  373.     makedirty(atline);
  374.     IFixMarks(startline, startchar, atline, atchar);
  375.     bp.p_line = atline;
  376.     bp.p_char = atchar;
  377.     this_cmd = YANKCMD;
  378.     getDOT();            /* Whatever used to be in linebuf */
  379.     return &bp;
  380. }
  381.  
  382. /* This is an attempt to reduce the amount of memory taken up by each line.
  383.    Without this each malloc of a line uses sizeof (LINE) + sizeof(HEADER)
  384.    where LINE is 3 words and HEADER is 1 word.
  385.    This is going to allocate memory in chucks of CHUNKSIZE * sizeof (LINE)
  386.    and divide each chuck into LINES.  A LINE is free in a chunk when its
  387.    line->l_dline == 0, so linefree sets dline to 0. */
  388.  
  389.  
  390.  
  391. struct chunk {
  392.     int    c_nlines;    /* Number of lines in this chunk
  393.                    (so they don't all have to be CHUNKSIZE long) */
  394.     LINE    *c_block;    /* Chunk of memory */
  395.     struct chunk    *c_nextfree;    /* Next chunk of lines */
  396. };
  397.  
  398. struct chunk    *fchunk = 0;
  399.  
  400. LINE    *ffline = 0;    /* First free line */
  401.  
  402. freeline(line)
  403. register LINE    *line;
  404. {
  405.     line->l_dline = 0;
  406.     line->l_next = ffline;
  407.     if (ffline)
  408.         ffline->l_prev = line;
  409.     line->l_prev = 0;
  410.     ffline = line;
  411. }
  412.  
  413. lfreelist(first)
  414. register LINE    *first;
  415. {
  416.     if (first)
  417.         lfreereg(first, lastline(first));
  418. }
  419.  
  420. /* Append region from line1 to line2 onto the free list of lines */
  421.  
  422. lfreereg(line1, line2)
  423. register LINE    *line1,
  424.         *line2;
  425. {
  426.     register LINE    *next,
  427.             *last = line2->l_next;
  428.  
  429.     while (line1 != last) {
  430.         next = line1->l_next;
  431.         freeline(line1);
  432.         line1 = next;
  433.     }
  434. }
  435.  
  436. newchunk()
  437. {
  438.     register LINE    *newline;
  439.     register int    i;
  440.     struct chunk    *f;
  441.     int    nlines = CHUNKSIZE;
  442.  
  443.     f = (struct chunk *) malloc((unsigned) sizeof (struct chunk));
  444.     if (f == 0)
  445.         return 0;
  446.     while (nlines > 0) {
  447.         f->c_block = (LINE *) malloc((unsigned) (sizeof (LINE) * nlines));
  448.         if (f->c_block != 0)
  449.             break;
  450.         nlines /= 2;
  451.     }
  452.     if (nlines <= 0)
  453.         return 0;
  454.  
  455.     f->c_nlines = nlines;
  456.     for (i = 0, newline = f->c_block; i < nlines; newline++, i++)
  457.         freeline(newline);
  458.     f->c_nextfree = fchunk;
  459.     fchunk = f;
  460.     return 1;
  461. }
  462.  
  463. LINE *
  464. nbufline()
  465. {
  466.     register LINE    *newline;
  467.  
  468.     if (ffline == 0) {    /* No free list */
  469.         if (newchunk() == 0)
  470.             complain("out of lines");
  471.     }
  472.     newline = ffline;
  473.     ffline = ffline->l_next;
  474.     if (ffline)
  475.         ffline->l_prev = 0;
  476.     return newline;
  477. }
  478.  
  479. /* Remove the free lines in chunk c from the free list because they are
  480.    no longer free. */
  481.  
  482. remfreelines(c)
  483. register struct chunk    *c;
  484. {
  485.     register LINE    *lp;
  486.     register int    i;
  487.  
  488.     for (lp = c->c_block, i = 0; i < c->c_nlines; i++, lp++) {
  489.         if (lp->l_prev)
  490.             lp->l_prev->l_next = lp->l_next;
  491.         else
  492.             ffline = lp->l_next;
  493.         if (lp->l_next)
  494.             lp->l_next->l_prev = lp->l_prev;
  495.     }
  496. }
  497.  
  498. /* This is/{should be} used to garbage collect the chunks of lines when
  499.    malloc fails and we are NOT looking for a new buffer line.  This goes
  500.    through each chunk, and if every line in a given chunk is not allocated,
  501.    the entire chunk is `free'd by "free()"  */
  502.  
  503. GCchunks()
  504. {
  505.     register struct chunk    *cp;
  506.     struct chunk    *prev = 0,
  507.             *next = 0;
  508.     register int    i;
  509.     register LINE    *newline;
  510.  
  511.     message("Garbage collecting ...");
  512.     UpdateMesg();
  513. #ifdef UNIX
  514.     sleep(1);
  515. #endif
  516.      for (cp = fchunk; cp; cp = next) {
  517.         for (i = 0, newline = cp->c_block; i < cp->c_nlines; newline++, i++)
  518.             if (newline->l_dline != 0)
  519.                 break;
  520.  
  521.          next = cp->c_nextfree;
  522.  
  523.         if (i == cp->c_nlines) {        /* Unlink it!!! */
  524.             if (prev)
  525.                 prev->c_nextfree = cp->c_nextfree;
  526.             else
  527.                 fchunk = cp->c_nextfree;
  528.             remfreelines(cp);
  529.             free((char *) cp->c_block);
  530.             free((char *) cp);
  531.         } else
  532.             prev = cp;
  533.     }
  534. }
  535. DoBrace()
  536. {
  537.     int c = LastKeyStruck;
  538.     if (c != '{') complain((char *) 0);
  539.     Insertc(c);
  540.      if (IsFlagSet(globflags,CMODE)) {
  541.          LineAI();
  542.          CTab();
  543.     }
  544.     redisplay();
  545. }
  546.  
  547.  
  548.  
  549.  
  550.  
  551.  
  552. /*-----------------------------o.s. dependent------------------------*/
  553. #ifndef UNIX
  554. sleep(n)
  555. {
  556.     int q;
  557.     int p = gcsec() & 0xff;
  558.     do {
  559.         q = gcsec() &0xff;
  560.         if(q < p) q +=100;
  561.     }while ((q - p) < 50);
  562. }
  563. #endif
  564.  
  565. /* end */
  566.